package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"util/log"
	"util/parser"
)

var (
	path     = flag.String("p", "", "entity define file's path")
	output   = flag.String("o", "", "parser file's output path")
	clear    = flag.Bool("c", false, "clear output path")
	initfunc = `package entity
import (
	. "data/datatype"
)

var objects = make(map[string]func()interface{})

//注册函数
func register(name string, createfunc func()interface{}) {
	if _, dup := objects[name]; dup {
		panic("entity: Register called twice for object " + name)
	}
	objects[name] = createfunc
}

//创建数据对象
func Create(name string) interface{} {
	if create, exist := objects[name]; exist {
		return create()
	}

	return nil
}

//获取类型
func GetType(name string) int {
	switch name {
		%s
	default:
		return 0
	}
}

//初始化函数
func init() {
	%s
}
`
	caseType = `
	case "%s":
		return %s`

	regfunc = `
	register("%s", func()interface{}{
		return Create%s()
	})`

	createfunc = `
//由子类调用的初始化函数
func (obj *%s) baseInit(dirty, modify map[string]interface{}) {
	//初始化表格
	obj.initRec()
	%s
}

//创建函数
func Create%s() *%s{
	obj := &%s{}
	obj.ObjectType = %s
	obj.initRec()
	%s
	return obj
}

`
	basefunc = `
	//初始化基类
	obj.%s.baseInit(dirty,modify)
`
)

func createEntity(obj parser.Object, outfile string) {

	//struct getset deffunc
	data := obj.CreateObj() + obj.CreatePropertys() + obj.CreateRecords()

	baseinit := `
	obj.mdirty = dirty
	obj.mmodify = modify
`

	//create func
	base := `
	obj.mdirty = make(map[string]interface{})
	obj.mmodify = make(map[string]interface{})`
	if obj.Base != "" {
		baseinit = fmt.Sprintf(basefunc, obj.Base)
		base = fmt.Sprintf("	obj.%s.baseInit(make(map[string]interface{}), make(map[string]interface{}))", obj.Base)
	}
	data += fmt.Sprintf(createfunc,
		obj.Name, baseinit,
		obj.Name, obj.Name,
		obj.Name,
		strings.ToUpper(obj.Type),
		base)

	//save file
	file, err := os.Create(outfile)
	if err != nil {
		fmt.Println("writer", err)
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	writer.WriteString(data)
	writer.Flush()

	cmd := exec.Command("gofmt", "--w", outfile)
	cmd.Run()

	log.TraceInfo("entity", "create file:", outfile)

}

func main() {
	flag.Parse()
	if *path == "" || *output == "" {
		fmt.Println("usage:datastruct -p ./entity -o ../src/data/entity [-c]")
		flag.PrintDefaults()
		return
	}

	if *clear {
		outdir, _ := os.Open(*output)
		outfiles, _ := outdir.Readdir(0)
		for _, f := range outfiles {
			if !f.IsDir() {
				err := os.Remove(*output + "/" + f.Name())
				if err != nil {
					fmt.Println(err)
					return
				}
				log.TraceInfo("entity", "delete file:", *output+"/"+f.Name())
			}
		}
	}

	dir, _ := os.Open(*path)
	files, _ := dir.Readdir(0)

	reg := ""
	ct := ""
	for _, f := range files {
		if !f.IsDir() {
			obj := parser.ParseEntity(*path + "/" + f.Name())
			createEntity(obj, *output+"/"+strings.Replace(f.Name(), ".xml", ".go", -1))
			reg += fmt.Sprintf(regfunc, obj.Name, obj.Name)
			ct += fmt.Sprintf(caseType, obj.Name, strings.ToUpper(obj.Type))
		}
	}

	file, err := os.Create(*output + "/" + "reg.go")
	if err != nil {
		fmt.Println("writer", err)
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	writer.WriteString(fmt.Sprintf(initfunc, ct, reg))
	writer.Flush()

	log.TraceInfo("entity", "create file:", *output+"/"+"reg.go")

	reader := bufio.NewReader(os.Stdin)
	log.TraceInfo("entity", "press any key to quit")
	reader.ReadString('\n')
}
